package com.smartmedi.ai.service;

import com.smartmedi.ai.domain.entity.JhInMr;
import com.smartmedi.ai.domain.entity.JhInMrFile;
import com.smartmedi.ai.mapper.JhInMrFileMapper;
import com.smartmedi.ai.mapper.JhInMrMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

/**
 * FTP文件采集服务
 */
@Service
@Slf4j
public class FileCollectionService {

    @Autowired
    private JhInMrMapper jhInMrMapper;

    @Autowired
    private JhInMrFileMapper jhInMrFileMapper;

    // 任务状态缓存
    private static final Map<String, TaskStatus> taskStatusMap = new ConcurrentHashMap<>();

    // 支持的文件类型
    private static final Pattern TXT_PATTERN = Pattern.compile(".*\\.txt$", Pattern.CASE_INSENSITIVE); // 匹配.txt（忽略大小写）
    private static final Pattern HTML_PATTERN = Pattern.compile(".*\\.html$", Pattern.CASE_INSENSITIVE); // 匹配.html（忽略大小写）

    /**
     * 开始FTP文件采集任务
     * @param params 采集参数
     * @return 任务ID
     */
    public String startFtpCollection(Map<String, Object> params) {
        // 生成任务ID
        String taskId = UUID.randomUUID().toString();
        
        // 创建任务状态对象
        TaskStatus status = new TaskStatus();
        status.setTaskId(taskId);
        status.setStatus("RUNNING");
        status.setStartTime(new Date());
        status.setPercent(0);
        status.setMessage("正在初始化FTP连接...");
        
        // 存储任务状态
        taskStatusMap.put(taskId, status);
        
        // 异步执行FTP采集
        collectFilesFromFtp(taskId, params);
        
        return taskId;
    }

    /**
     * 获取任务状态
     * @param taskId 任务ID
     * @return 任务状态
     */
    public TaskStatus getTaskStatus(String taskId) {
        return taskStatusMap.getOrDefault(taskId, new TaskStatus());
    }

    /**
     * 异步执行FTP文件采集
     * @param taskId 任务ID
     * @param params 采集参数
     */
    @Async
    public void collectFilesFromFtp(String taskId, Map<String, Object> params) {
        TaskStatus status = taskStatusMap.get(taskId);
        FTPClient ftpClient = null;
        
        try {
            // 获取FTP配置
            Map<String, Object> ftpConfig = (Map<String, Object>) params.get("ftpConfig");
            String host = (String) ftpConfig.get("host");
            int port = (int) ftpConfig.get("port");
            String username = (String) ftpConfig.get("username");
            String password = (String) ftpConfig.get("password");
            
            // 获取其他参数
            String collectType = (String) params.get("collectType");
            int maxCount = params.containsKey("maxCount") ? (int) params.get("maxCount") : 100;
            
            // 连接FTP服务器
            ftpClient = new FTPClient();
            ftpClient.connect(host, port);
            boolean login = ftpClient.login(username, password);
            
            if (!login) {
                throw new IOException("FTP登录失败，请检查用户名和密码");
            }
            
            // 设置被动模式
            ftpClient.enterLocalPassiveMode();
            // 设置二进制传输模式
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            
            status.setMessage("连接FTP服务器成功，开始查询需要采集的病历...");
            
            // 查询需要采集的病历记录
            List<JhInMr> mrRecords = getMrRecords(collectType, params);
            
            if (mrRecords.isEmpty()) {
                status.setStatus("COMPLETED");
                status.setMessage("没有找到需要采集的病历记录");
                status.setPercent(100);
                return;
            }
            
            // 限制最大采集数量
            if (mrRecords.size() > maxCount) {
                mrRecords = mrRecords.subList(0, maxCount);
            }
            
            status.setTotalFiles(mrRecords.size());
            status.setMessage("找到 " + mrRecords.size() + " 条病历记录，开始采集文件...");
            
            // 开始采集文件
            int successCount = 0;
            int failCount = 0;
            
            for (int i = 0; i < mrRecords.size(); i++) {
                JhInMr mr = mrRecords.get(i);
                
                // 更新进度
                status.setPercent((i * 100) / mrRecords.size());
                status.setMessage("正在处理第 " + (i + 1) + "/" + mrRecords.size() + " 条记录: ");
                
                try {
                    String ftpPath = generateFtpPath(mr.getHisPatId());
                    
                    if (ftpPath != null) {
                        // 采集该路径下的文件
                        List<JhInMrFile> files = collectFilesFromPath(ftpClient, ftpPath, mr);
                        
                        if (!files.isEmpty()) {
                            successCount += files.size();
                            status.setCollectedFiles(successCount);
                        }
                    }
                } catch (Exception e) {
                    log.error("采集文件失败: {}, 错误: {}", mr.getMrCode(), e.getMessage(), e);
                    failCount++;
                }
            }
            
            // 更新最终状态
            status.setStatus("COMPLETED");
            status.setPercent(100);
            status.setMessage("采集完成，成功: " + successCount + "，失败: " + failCount);
            status.setEndTime(new Date());
            
        } catch (Exception e) {
            log.error("FTP文件采集任务执行失败: {}", e.getMessage(), e);
            status.setStatus("FAILED");
            status.setErrorMsg(e.getMessage());
            status.setEndTime(new Date());
        } finally {
            if (ftpClient != null && ftpClient.isConnected()) {
                try {
                    ftpClient.logout();
                    ftpClient.disconnect();
                } catch (IOException e) {
                    log.error("关闭FTP连接失败", e);
                }
            }
        }
    }

    /**
     * 根据IN_MR_SN生成FTP路径（不足10位前面补0至10位）
     * @param inMrSn IN_MR_SN值
     * @return FTP路径
     */
    private String generateFtpPath(String inMrSn) {
        if (inMrSn == null) {
            return null;
        }

        // 步骤1：不足10位则前面补0，确保总长度为10位
        int targetLength = 10;
        int currentLength = inMrSn.length();
        StringBuilder padding = new StringBuilder();
        // 计算需要补0的数量（若长度已超过10位，不补位，直接截取前10位）
        int paddingCount = Math.max(0, targetLength - currentLength);
        for (int i = 0; i < paddingCount; i++) {
            padding.append("0");
        }
        // 拼接补位后的字符串（若原长度超过10位，截取前10位）
        String pathPart = padding.append(inMrSn).toString();
        if (pathPart.length() > targetLength) {
            pathPart = pathPart.substring(0, targetLength);
        }

        // 步骤2：每2个字符一组，生成层级路径
        StringBuilder path = new StringBuilder();
        for (int i = 0; i < pathPart.length(); i += 2) {
            // 截取2个字符（避免最后一次循环索引越界）
            int endIndex = Math.min(i + 2, pathPart.length());
            path.append("/").append(pathPart.substring(i, endIndex));
        }

        return path.toString();
    }
    
    /**
     * 从FTP路径采集文件（递归，保持本地目录结构，E:/bingli/ftpPath/fileName）
     * @param ftpClient FTP客户端
     * @param ftpPath FTP路径（绝对路径，和FTP目录结构一致）
     * @param mr 病历记录
     * @return 采集的文件列表
     */
    private List<JhInMrFile> collectFilesFromPath(FTPClient ftpClient, String ftpPath, JhInMr mr) throws IOException {
        List<JhInMrFile> collectedFiles = new ArrayList<>();
        boolean success = ftpClient.changeWorkingDirectory(ftpPath);
        if (!success) {
            log.warn("FTP路径不存在: {}", ftpPath);
            return collectedFiles;
        }
        FTPFile[] ftpFiles = ftpClient.listFiles();
        if (ftpFiles == null || ftpFiles.length == 0) {
            return collectedFiles;
        }
        for (FTPFile ftpFile : ftpFiles) {
            String fileName = ftpFile.getName();
            if (ftpFile.isDirectory() && !fileName.equals(".") && !fileName.equals("..")) {
                String subDirPath = ftpPath.endsWith("/") ? ftpPath + fileName : ftpPath + "/" + fileName;
                collectedFiles.addAll(collectFilesFromPath(ftpClient, subDirPath, mr));
            } else if (ftpFile.isFile() && (TXT_PATTERN.matcher(fileName).matches() || HTML_PATTERN.matcher(fileName).matches())) {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                boolean downloaded = ftpClient.retrieveFile(fileName, outputStream);
                // 文件另存一份到本地，保持目录结构 E:/bingli/ftpPath/fileName
                String localDir = "E:/bingli" + (ftpPath.startsWith("/") ? ftpPath : "/" + ftpPath);
                File localFile = new File(localDir, fileName);
                File parentDir = localFile.getParentFile();
                if (!parentDir.exists()) {
                    parentDir.mkdirs();
                }
                FileUtils.writeByteArrayToFile(localFile, outputStream.toByteArray());
                if (downloaded) {
                    JhInMrFile fileRecord = new JhInMrFile();
                    fileRecord.setFileName(fileName);
                    fileRecord.setFileType(getContentType(fileName));
                    fileRecord.setFileContent(Base64.getEncoder().encodeToString(outputStream.toByteArray()));
                    fileRecord.setFileSize((long) outputStream.size());
                    fileRecord.setRecordId(mr.getRowkey() != null ? mr.getRowkey().toString() : "");
                    fileRecord.setFileDesc("FTP自动采集 - " + ftpPath);
                    fileRecord.setUploadUser("系统自动采集");
                    fileRecord.setUploadTime(new Date());
                    fileRecord.setCreateTime(new Date());
                    fileRecord.setUpdateTime(new Date());
                    collectedFiles.add(fileRecord);
                }
            }
        }
        return collectedFiles;
    }
    
    /**
     * 获取文件的Content-Type
     * @param fileName 文件名
     * @return Content-Type
     */
    private String getContentType(String fileName) {
        if (fileName == null) {
            return "application/octet-stream";
        }
        
        fileName = fileName.toLowerCase();
        
        if (fileName.endsWith(".txt")) {
            return "text/plain";
        } else if (fileName.endsWith(".doc")) {
            return "application/msword";
        } else if (fileName.endsWith(".docx")) {
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        } else {
            return "application/octet-stream";
        }
    }
    
    /**
     * 根据条件查询需要采集的病历记录
     * @param collectType 采集类型
     * @param params 参数
     * @return 病历记录列表
     */
    private List<JhInMr> getMrRecords(String collectType, Map<String, Object> params) {
        //TODO
        // 实际项目中，应该根据不同的collectType查询不同的数据
        // 这里为了简化，直接返回一些测试数据
        
        // 模拟从数据库查询数据
        List<JhInMr> records = new ArrayList<>();
        JhInMr job = new JhInMr();
        JhInMr mr = new JhInMr();
        JhInMr sd = new JhInMr();
        JhInMr sd2 = new JhInMr();
        JhInMr sd3 = new JhInMr();

        job.setHisPatId("2004353");
        mr.setHisPatId("6094302");
        sd.setHisPatId("Z0482329");
        sd2.setHisPatId("82412624");
        sd3.setHisPatId("6084449");

        records.add(mr);
        records.add(sd);
        records.add(sd2);
        records.add(sd3);
        
        return records;
    }
    
    /**
     * 任务状态类
     */
    @Data
    public static class TaskStatus {
        private String taskId;
        private String status;  // RUNNING, COMPLETED, FAILED
        private int percent;
        private String message;
        private String errorMsg;
        private int totalFiles;
        private int collectedFiles;
        private Date startTime;
        private Date endTime;
    }
} 